package main

import (
	"bufio"
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"jz/config"
	"jz/handlers"

	"net"

	"time"

	_ "github.com/go-sql-driver/mysql"
	"gopkg.in/yaml.v2"
)

func writeJSON(w http.ResponseWriter, data interface{}, status int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(data)
}

// 初始化配置
func initConfig() (*config.Config, error) {
	configData, err := os.ReadFile("config.yaml")
	if err != nil {
		return nil, fmt.Errorf("读取配置文件失败: %v", err)
	}

	var cfg config.Config
	if err := yaml.Unmarshal(configData, &cfg); err != nil {
		return nil, fmt.Errorf("解析配置文件失败: %v", err)
	}
	return &cfg, nil
}

// 初始化数据库连接
func initDB(cfg *config.Config) (*sql.DB, error) {
	db, err := sql.Open("mysql", cfg.Database.GetDSN())
	if err != nil {
		return nil, fmt.Errorf("数据库连接失败: %v", err)
	}

	if err = db.Ping(); err != nil {
		db.Close()
		return nil, fmt.Errorf("数据库连接测试失败: %v", err)
	}

	return db, nil
}

// 获取用户输入的表名
func getTableNameFromUser(cfg *config.Config) (string, bool, error) {
	// 创建一个带缓冲的通道用于接收用户输入
	inputChan := make(chan string, 1)
	errChan := make(chan error, 1)

	// 在goroutine中读取用户输入
	go func() {
		reader := bufio.NewReader(os.Stdin)
		currentTable := ""
		if cfg != nil {
			currentTable = cfg.TableName
		}
		fmt.Printf("请输入要导入的表名(直接回车使用上次的表名 %s，5秒后自动使用上次的表名): ", currentTable)
		input, err := reader.ReadString('\n')
		if err != nil {
			errChan <- fmt.Errorf("读取输入失败: %v", err)
			return
		}
		inputChan <- input
	}()

	// 等待用户输入或超时
	select {
	case input := <-inputChan:
		tableName := strings.TrimSpace(input)
		if tableName == "" {
			if cfg == nil || cfg.TableName == "" {
				return "", false, fmt.Errorf("没有保存的表名，请输入表名")
			}
			return cfg.TableName, true, nil
		}
		return tableName, false, nil
	case err := <-errChan:
		return "", false, err
	case <-time.After(5 * time.Second):
		fmt.Println("\n已超时，使用上次的表名")
		if cfg == nil || cfg.TableName == "" {
			return "", false, fmt.Errorf("没有保存的表名，请输入表名")
		}
		return cfg.TableName, true, nil
	}
}

// 更新配置文件
func updateConfig(cfg *config.Config, columns []config.ColumnConfig, tableName string) error {
	cfg.Tables = config.TablesConfig{
		Transactions: config.TableConfig{
			Columns: columns,
		},
	}
	cfg.TableName = tableName // 保存表名

	newConfigData, err := yaml.Marshal(cfg)
	if err != nil {
		return fmt.Errorf("生成配置文件失败: %v", err)
	}

	if err := os.WriteFile("config.yaml", newConfigData, 0644); err != nil {
		return fmt.Errorf("保存配置文件失败: %v", err)
	}

	return nil
}

func main() {
	// 初始化配置
	cfg, err := initConfig()
	if err != nil {
		log.Fatal(err)
	}

	// 初始化数据库连接
	db, err := initDB(cfg)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	log.Println("数据库连接成功！")

	// 获取表名
	tableName, skipConfig, err := getTableNameFromUser(cfg)
	if err != nil {
		log.Fatal(err)
	}

	if !skipConfig {
		// 获取表结构
		columns, err := getTableColumns(db, tableName)
		if err != nil {
			log.Fatal("获取表结构失败:", err)
		}

		// 更新配置
		if err := updateConfig(cfg, columns, tableName); err != nil {
			log.Fatal(err)
		}

		log.Printf("表 %s 的结构已成功更新到配置文件\n", tableName)
	} else {
		log.Println("使用现有配置")
	}

	// 创建处理器并设置路由
	handler := handlers.NewTransactionHandler(db, cfg, tableName)
	setupRoutes(handler, cfg) // 传入配置对象

	// 获取服务端口
	port := 8080 // 默认端口
	if cfg.Server.Port > 0 {
		port = cfg.Server.Port
	}

	// 启动服务器
	serverAddr := fmt.Sprintf(":%d", port)
	log.Printf("服务器启动在 %s 端口\n", serverAddr)
	if err := http.ListenAndServe(serverAddr, nil); err != nil {
		log.Fatal(err)
	}
}

// 设置HTTP路由
// 设置HTTP路由
func setupRoutes(handler *handlers.TransactionHandler, cfg *config.Config) {
    // 添加静态文件服务
    http.Handle("/html/", http.StripPrefix("/html/", http.FileServer(http.Dir("html"))))
    
    // API保存路由
    http.HandleFunc("/api/account/apiSave", handler.HandleApiSave)
    
    // 获取本机IP地址
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        log.Printf("获取IP地址失败: %v\n", err)
        return
    }

    // 查找第一个非回环IP地址
    var ip string
    for _, addr := range addrs {
        if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                ip = ipnet.IP.String()
                break
            }
        }
    }

    if ip == "" {
        ip = "localhost"
    }

    // 获取服务端口
    port := 8080 // 默认端口
    if cfg.Server.Port > 0 {
        port = cfg.Server.Port
    }

    // 输出所有可用的API接口地址
    log.Println("\n可用的API接口：")
    log.Println("1. 交易记录保存接口")
    log.Printf("   - URL: http://%s:%d/api/account/apiSave", ip, port)
    log.Printf("   - 方法: POST")
    log.Printf("   - 功能: 批量保存交易记录")
    log.Printf("   - 请求格式示例:")
    log.Printf(`   {
        "month": "2024-03",
        "transactions": [
            {
                "date": "2024-03-15",
                "time": "14:30:00",
                "type": "expense",
                "category": "日用品",
                "amount": 100.50,
                "remark": "购物"
            }
        ]
    }`)
    log.Println("\n响应格式：")
    log.Printf(`   {
        "success": true/false,
        "message": "响应消息",
        "timestamp": 1710486000000
    }`)
    log.Println("")

    // 添加统计接口路由
    statsHandler := handlers.NewStatisticsHandler(handler.GetDB(), cfg, cfg.TableName)
    http.HandleFunc("/api/statistics", statsHandler.HandleStatistics)
    http.HandleFunc("/api/statistics/monthly", statsHandler.HandleMonthlyDetail)
    log.Println("\n2. 统计页面")
    log.Printf("   - 访问地址: http://%s:%d/html/statistics.html", ip, port)
    log.Printf("   - 功能: 查看收支统计图表")
    log.Printf("   - 统计数据接口: http://%s:%d/api/statistics?year=2024", ip, port)
    log.Printf("   - 支持功能:")
    log.Printf("     * 按年份查看收支统计")
    log.Printf("     * 月度收支对比")
    log.Printf("     * 收支类型分布\n")
}

func getTableColumns(db *sql.DB, tableName string) ([]config.ColumnConfig, error) {
	query := `
		SELECT 
			COLUMN_NAME,
			COLUMN_TYPE,
			IS_NULLABLE,
			COLUMN_KEY,
			EXTRA,
			COLUMN_DEFAULT
		FROM 
			INFORMATION_SCHEMA.COLUMNS 
		WHERE 
			TABLE_SCHEMA = DATABASE() 
			AND TABLE_NAME = ?
		ORDER BY 
			ORDINAL_POSITION`

	rows, err := db.Query(query, tableName)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var columns []config.ColumnConfig
	for rows.Next() {
		var (
			name         string
			columnType   string
			isNullable   string
			columnKey    string
			extra        string
			defaultValue sql.NullString
		)

		err := rows.Scan(&name, &columnType, &isNullable, &columnKey, &extra, &defaultValue)
		if err != nil {
			return nil, err
		}

		column := config.ColumnConfig{
			Name:          name,
			Type:          strings.ToUpper(columnType),
			Nullable:      isNullable == "YES",
			PrimaryKey:    columnKey == "PRI",
			AutoIncrement: strings.Contains(strings.ToLower(extra), "auto_increment"),
		}

		if defaultValue.Valid {
			column.Default = defaultValue.String
		}

		columns = append(columns, column)
	}

	return columns, nil
}
